package com.lehecai.ucenter.dao.impl;

import java.io.Serializable;
import java.math.BigInteger;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import com.lehecai.ucenter.dao.BaseDao;
import com.lehecai.ucenter.dao.BaseQuery;
import com.lehecai.ucenter.dao.HibernateQuery;
import com.lehecai.ucenter.dao.QueryConstant;
import com.lehecai.ucenter.dao.QueryOrder;
import com.lehecai.ucenter.dao.QueryParam;
import com.lehecai.ucenter.dao.QueryWhere;
import com.lehecai.ucenter.utils.PageBean;
import com.lehecai.ucenter.utils.ReflectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BaseDaoImpl<T, ID extends Serializable> implements BaseDao<T,ID> {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());

	private Class<T> entityClass;
    private SessionFactory sessionFactory;
    
	public BaseDaoImpl(){
    	this.entityClass = ReflectionUtils.getSuperClassGenricType(getClass());
    }
	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	@SuppressWarnings("unchecked")
	@Override
	public T get(ID paramID) {
		return (T)getSession().get(this.entityClass, paramID);
	}
	
	public List<T> getAll(){
		return findList(null);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> findList(QueryParam queryParam) {
		if(queryParam == null){
			queryParam = new QueryParam();
		}
		if(StringUtils.isEmpty(queryParam.getEntityName())){
			queryParam.setEntityName(entityClass.getSimpleName());
		}
		BaseQuery bq = new HibernateQuery();
		bq.setQueryParam(queryParam);
		Query query = createQuery(bq,queryParam);
		return query.list();
	}

	@Override
	public int count(QueryParam queryParam) {
		if(StringUtils.isEmpty(queryParam.getEntityName())){
			queryParam.setEntityName(entityClass.getName());
		}
		BaseQuery bq = new HibernateQuery();
		bq.setQueryParam(queryParam);
		bq.setCount(true);
		queryParam.getPageBean().setPageFlag(false);
		Query query = createQuery(bq,queryParam);
		Object object = query.uniqueResult();
		int i = 0;
		if (object != null) {
			if(object instanceof BigInteger){
				i = ((BigInteger) object).intValue();
			}else if(object instanceof Long){
				i = ((Long) object).intValue();
			}
		}
		return i;
	}
	
	private Query createQuery(BaseQuery baseQuery, QueryParam queryParam){
		StringBuffer hql = new StringBuffer(baseQuery.toSelectString());
		Map<String, QueryWhere> paramsWhere = queryParam.getParamsWhere();
		if (paramsWhere != null) {
			hql.append(baseQuery.toQueryString());
		}
		
		List<QueryOrder> orders = queryParam.getOrders(); 
		if(orders != null) {
			hql.append(baseQuery.toOrderString());
		}
		Query query = null;
		query = getSession().createQuery(hql.toString());
		if (paramsWhere != null) {
			for (Iterator<String> iterator = paramsWhere.keySet().iterator(); iterator.hasNext();) {
				String key = iterator.next();
				QueryWhere queryWhere = paramsWhere.get(key);
				if(queryWhere.getOperator().equals(QueryConstant.QUERY_OP_IN)){
					query.setParameterList(key, queryWhere.getValues());
				}else{
					query.setParameter(key, queryWhere.getValue());
				}
			}
		}
		PageBean pageBean = queryParam.getPageBean();
		if (pageBean != null && pageBean.isPageFlag()) {
			if (pageBean.getPage() > 0) {
				query.setFirstResult((pageBean.getPage() - 1)
						* pageBean.getPageSize());
			}
			if (pageBean.getPageSize() > 0) {
				query.setMaxResults(pageBean.getPageSize());
			}
		}
		return query;
	}

	@Override
	public void persist(T paramT) {
        getSession().persist(paramT);  
	}

	@SuppressWarnings("unchecked")
	@Override
	public T merge(T paramT) {
		return (T) getSession().merge(paramT); 
	}

	@Override
	public void delete(T paramT) {
		getSession().delete(paramT);
	}
	
	@Override
	public void delete(ID id) {
		getSession().delete(get(id));
	}

	@Override
	public void flush() {
		getSession().flush();
	}
}
